The dbhDoubleBack field of a double buffer header specifies the address of a doubleback procedure, an application-defined procedure that is called when the double buffers are switched and the exhausted buffer needs to be refilled. The doubleback procedure should have this format:
PROCEDURE MyDoubleBackProc (chan: SndChannelPtr;
exhaustedBuffer: SndDoubleBufferPtr);
The primary responsibility of the doubleback procedure is to refill an exhausted buffer of samples and to mark the newly filled buffer as ready for processing. Listing 1-45 illustrates how to define a doubleback procedure. Note that the sound channel pointer passed to the doubleback procedure is not used in this procedure.
This doubleback procedure extracts the address of its local variables from the dbUserInfo field of the double buffer record passed to it. These variables are used to keep track of how many total bytes need to be copied and how many bytes have been copied so far. Then the procedure copies at most a bufferfull of bytes into the empty buffer and updates several fields in the double buffer record and in the structure containing the local variables. Finally, if all the bytes to be copied have been copied, the buffer is marked as the last buffer.
Because the doubleback procedure is called at interrupt time, it cannot make any calls that move memory either directly or indirectly. (Despite its name, the BlockMove procedure does not cause blocks of memory to move or be purged, so you can safely call it in your doubleback procedure, as illustrated in Listing 1-45 .)
Listing 45 Defining a doubleback procedure
PROCEDURE MyDoubleBackProc (chan: SndChannelPtr;
doubleBuffer: SndDoubleBufferPtr);
VAR
myVarsPtr: LocalVarsPtr;
myNumBytes: LongInt;
BEGIN
{Get pointer to my local variables.}
myVarsPtr := LocalVarsPtr(doubleBuffer^.dbUserInfo[0]);
{Get number of bytes left to copy.}
myNumBytes := myVarsPtr^.bytesTotal - myVarsPtr^.bytesCopied;
{If the amount left is greater than double buffer size, limit the number }
{ of bytes to copy to the size of the buffer.}
IF myNumBytes > kDoubleBufferSize THEN
myNumBytes := kDoubleBufferSize;
{Copy samples to double buffer.}
BlockMove(myVarsPtr^.dataPtr, @doubleBuffer^.dbSoundData[0], myNumBytes);
{Store number of samples in buffer and mark buffer as ready.}
doubleBuffer^.dbNumFrames := myNumBytes;
doubleBuffer^.dbFlags := BOR(doubleBuffer^.dbFlags, dbBufferReady);
{Update data pointer and number of bytes copied.}
myVarsPtr^.dataPtr := Ptr(ORD4(myVarsPtr^.dataPtr) + myNumBytes);
myVarsPtr^.bytesCopied := myVarsPtr^.bytesCopied + myNumBytes;
{If all samples have been copied, then this is the last buffer.}
IF myVarsPtr^.bytesCopied = myVarsPtr^.bytesTotal THEN
doubleBuffer^.dbFlags := BOR(doubleBuffer^.dbFlags, dbLastBuffer);
END;
| Previous | Chapter contents | Chapter top | Section top | Next |